﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Djs.Games.DeskGame.GameComponents
{
    /// <summary>
    /// Řídí automatické pohybování danou figurkou.
    /// Umožňuje generovat trasy pohybu.
    /// </summary>
    public class GameAnimator
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="animatedItem"></param>
        /// <param name="pathPoints"></param>
        /// <param name="reDrawLayer"></param>
        public GameAnimator(IItem animatedItem, IEnumerable<GameAnimatorPathPoint> pathPoints, Action<int> reDrawLayer)
        {
            this.AnimatedItem = animatedItem;
            this.PathPoints = new List<GameAnimatorPathPoint>(pathPoints);
            this.ReDrawLayer = reDrawLayer;
        }
        #endregion
        #region Public property
        /// <summary>
        /// Prvek, který se bude animovat.
        /// Animace se provádí tak, že se opakovaně volá metoda IItem.RunAction(ActionType.AnimationRun, souřadnice), a následně se vyvolá překreslení vrstvy IItem.VisualLayer.
        /// Povolení animace prvku je zjištěno metodou IItem.EnableAction(ActionType.
        /// </summary>
        public IItem AnimatedItem { get; set; }
        /// <summary>
        /// Položky animované cesty.
        /// </summary>
        public List<GameAnimatorPathPoint> PathPoints { get; set; }
        /// <summary>
        /// Metoda, která se volá pro překreslení vrstvy, která obsahuje AnimatedItem.
        /// </summary>
        public Action<int> ReDrawLayer { get; set; }
        #endregion
        #region Public metody (start, stop), proces animace
        /// <summary>
        /// Nastartuje animaci
        /// </summary>
        public void Start()
        {
            if (this._BackThread == null)
            {
                this._BackThread = new System.Threading.Thread(this._ThreadEntryPoint);
                this._BackThread.Start();
            }
            else
                throw new InvalidOperationException("Class GameAnimator cannot be started, when animation process is running.");
        }
        /// <summary>
        /// Zruší animaci, možno volat kdykoliv.
        /// </summary>
        public void Cancel()
        {
            this._Cancel = true;
        }
        /// <summary>
        /// Výkonná metoda threadu na pozadí
        /// </summary>
        private void _ThreadEntryPoint()
        {
            this._CurrentPointer = 0;
            this._Cancel = false;
            if (this.PathPoints != null && this._CurrentPointer < this.PathPoints.Count)
            {
                // Zahájení animace se volá explicitně:
                this.AnimatedItem.RunAction(ActionType.AnimationBegin, this.PathPoints[0].Point);

                // Běh animace:
                while (this._CurrentPointer < this.PathPoints.Count)
                {
                    this._ApplyCurrentPoint();
                    this._CurrentPointer++;

                    // Pokud bych přidával další logiku (například cykly, přeskoky, atd), bude to zde:

                }
            }
            // Konec animace se volá explicitně, vždy i když animace neběžela (prvek s tím počítá):
            if (this.AnimatedItem.RunAction(ActionType.AnimationEnd, PointF.Empty))
                this.ReDrawLayer(this.AnimatedItem.VisualLayer);

            this._BackThread = null;
        }
        /// <summary>
        /// Provede animaci dle daného jednoho bodu.
        /// Animace = najde položku animace this.PathPoints[this._CurrentPointer];
        /// její souřadnici vloží do Item přes metodu RunAction(ActionType.AnimationRun, point);
        /// zavolá překreslení vrstvy,
        /// a dá si šlofíka na daný počet milisekund.
        /// </summary>
        private void _ApplyCurrentPoint()
        {
            if (this._CurrentPointer >= this.PathPoints.Count) return;
            
            GameAnimatorPathPoint pathPoint = this.PathPoints[this._CurrentPointer];
            if (this.AnimatedItem.RunAction(ActionType.AnimationRun, pathPoint.Point))
                this.ReDrawLayer(this.AnimatedItem.VisualLayer);

            System.Threading.Thread.Sleep(pathPoint.DelayAfter);
        }
        private System.Threading.Thread _BackThread;
        private int _CurrentPointer;
        private bool _Cancel;
        #endregion
    }
    /// <summary>
    /// Jedna položka animátoru (souřadnice a doba, po kterou na ní bude položka vidět, než se přesune na další položku).
    /// </summary>
    public class GameAnimatorPathPoint
    {
        /// <summary>
        /// Vizuální souřadnice
        /// </summary>
        public PointF Point { get; set; }
        /// <summary>
        /// Prodlení na souřadnici, v milisekundách.
        /// </summary>
        public int DelayAfter { get; set; }
    }
}
